import Vue from 'vue'
import axios from 'axios'
import store from '_store/index'
import config from '_config/index'
import { apiList } from '../api'

const THAT = Vue.prototype

class HttpRequest {
  constructor() {
    this.queue = {}
  }

  // * 单例获取对象
  static getInstance() {
    if (!this.instance) {
      this.instance = new HttpRequest()
    }
    return this.instance
  }

  /**
   * @description 获取axios默认配置
   * @author fanzhongxu
   * @returns config
   */
  getDefaultConfig() {
    return {
      baseURL: config.baseURL,
    }
  }

  /**
   * @description 显示全局loading
   * @author fanzhongxu
   */
  showLoading() {
    if (Object.keys(this.queue).length === 0) {
      // 显示spin
      store.commit('setSpinning', true)
    }
  }

  /**
   * @description 关闭全局Loading
   * @author fanzhongxu
   */
  hideLoading() {
    if (Object.keys(this.queue).length <= 0) {
      // 隐藏spin
      store.commit('setSpinning', false)
    }
  }

  /**
   * @description 请求&响应拦截器
   * @author fanzhongxu
   * @param {Object} instance axios实例
   * @param {String} url api-url
   * @param {Boolean} loading 全局loading
   */
  interceptors(instance, url, loading) {
    instance.interceptors.request.use(
      config => {
        loading && this.showLoading()
        this.queue[url] = true // 入队
        return config
      },
      err => {
        return Promise.reject(err)
      }
    )

    instance.interceptors.response.use(
      res => {
        delete this.queue[url] // 出队
        loading && this.hideLoading()
        const { data } = res
        return data
      },
      err => {
        delete this.queue[url] // 出队
        loading && this.hideLoading()
        return Promise.reject(err)
      }
    )
  }

  /**
   * @description 请求方法
   * @author fanzhongxu
   * @param {*} options axios配置
   * @returns 请求结果
   */
  request(options) {
    const instance = axios.create()

    options = Object.assign({}, this.getDefaultConfig(), options)

    this.interceptors(instance, options.url, options.loading)

    return instance(options)
  }
}

/**
 * @description ajax方法
 * @author fanzhongxu
 * @param {String} url api接口地址
 * @param {Object} params api-get接口参数
 * @param {Object} data api-post接口参数
 * @param {String} method api接口方式
 * @param {String} loading 是否显示全局loading
 * @param {Object} header 请求头信息
 */
const _ajax = function({ url, params, data, method, loading, headers }) {
  headers.ticket = store.state.ticket
  return new Promise((resolve, reject) => {
    const ajaxRequest = HttpRequest.getInstance()
    ajaxRequest
      .request({
        url,
        params,
        data,
        method,
        headers,
        loading,
      })
      .then(res => {
        resolve(res)
      })
      .catch(err => {
        if (err.response && err.response.status === 404) {
          THAT.alertError('网络中断，请稍后重试')
        } else if (err.response && err.response.status === 500) {
          THAT.alertError('网络繁忙，请稍后重试')
        } else if (err.response && err.response.status === 503) {
          THAT.alertError('服务器异常，请稍后重试')
        } else if (err.response && err.response.status === 401) {
          THAT.$router.push('/login')
        }
        reject(err)
      })
  })
}

/**
 * @description ajax-get方法
 * @author fanzhongxu
 * @param {String} api api接口名
 * @param {Object} params api接口参数
 * @param {Boolean} loading 是否显示全局loading，默认false（不显示）
 * @param {Object} header 请求头信息 默认空对象{}
 */
const $get = function(
  api,
  params = {},
  { loading = false, headers = {} } = {}
) {
  const options = {
    url: apiList[api],
    params,
    method: 'GET',
    loading,
    headers,
  }
  return _ajax(options)
}

/**
 * @description ajax-post方法
 * @author fanzhongxu
 * @param {String} api api接口名
 * @param {Object} data api接口参数
 * @param {Boolean} loading 是否显示全局loading，默认false（不显示）
 * @param {Object} header 请求头信息 默认空对象{}
 */
const $post = function(api, data = {}, { loading = false, headers = {} } = {}) {
  const options = {
    url: apiList[api],
    data,
    method: 'POST',
    loading,
    headers,
  }
  return _ajax(options)
}

/**
 * @description ajax-delete方法
 * @author fanzhongxu
 * @param {String} api api接口名
 * @param {Object} params api接口参数
 * @param {Boolean} loading 是否显示全局loading，默认false（不显示）
 * @param {Object} header 请求头信息 默认空对象{}
 */
const $delete = function(
  api,
  params = {},
  { loading = false, headers = {} } = {}
) {
  const options = {
    url: apiList[api],
    params,
    method: 'DELETE',
    loading,
    headers,
  }
  return _ajax(options)
}

/**
 * @description ajax-put方法
 * @author fanzhongxu
 * @param {String} api api接口名
 * @param {Object} params api接口参数
 * @param {Boolean} loading 是否显示全局loading，默认false（不显示）
 * @param {Object} header 请求头信息 默认空对象{}
 */
const $put = function(api, data = {}, { loading = false, headers = {} } = {}) {
  const options = {
    url: apiList[api],
    data,
    method: 'PUT',
    loading,
    headers,
  }
  return _ajax(options)
}

/**
 * @description ajax-put方法
 * @author fanzhongxu
 * @param {String} api api接口名
 * @param {Object} params api接口参数
 * @param {Boolean} loading 是否显示全局loading，默认false（不显示）
 * @param {Object} header 请求头信息 默认空对象{}
 */
const $patch = function(
  api,
  data = {},
  { loading = false, headers = {} } = {}
) {
  const options = {
    url: apiList[api],
    data,
    method: 'PATCH',
    loading,
    headers,
  }
  return _ajax(options)
}

const ajax = { $get, $post, $delete, $put, $patch }

export default ajax
